#include "widget.h"
#include "ui_widget.h"
#include "QtMath"
#include <QtEndian>
#include "QFileDialog"
#include "QTimer"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    m_img = new QImage(IMG_WIDTH,IMG_HEIGHT,QImage::Format_RGB16);
//    startWorkInAThread();
    initAudio();
    workerThread = nullptr;
}

Widget::~Widget()
{
    delete ui;
}

void Widget::startWorkInAThread()
{
    if(workerThread){
        connect(workerThread, &WorkerThread::update_img_signal, this, &Widget::update_img_slot);
        connect(workerThread, &WorkerThread::finished, workerThread, &QObject::deleteLater);
//            connect(workerThread, &WorkerThread::finished, workerThread, [](){qDebug()<<"线程完成信号";});
        workerThread->start();
    }
}

void Widget::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event);

    QPainter paint(this);
    int w = width();
    int h = height();

    QImage img =m_img->scaled(w,h,Qt::IgnoreAspectRatio,Qt::SmoothTransformation);

    paint.drawImage(0,0,img);


}

void Widget::keyPressEvent(QKeyEvent *event)
{
    int val = event->key();
    extern void add_key(int keyval );
    add_key(val);
//    qDebug()<<val;
}

void Widget::keyReleaseEvent(QKeyEvent *event)
{
    int val = event->key();
    extern void remove_key(int keyval );
    remove_key(val);
}

void Widget::mousePressEvent(QMouseEvent *event)
{
    Q_UNUSED(event);
    QString s = QFileDialog::getOpenFileName(this, tr("Open File"),
                                 "./",
                                 tr("games (*.nes)"));
    if(s.isEmpty()){
        return ;
    }else{

    }
    if(workerThread){
        workerThread->set_quit(1);

        workerThread = new WorkerThread;

    }else{
        workerThread = new WorkerThread;
    }
    workerThread->set_file_name(s);
    QTimer::singleShot(1000,this,&Widget::startWorkInAThread);
}


void Widget::update_img_slot(int s)
{

    if(s){
        quint16 *imgp=(quint16 *)m_img->bits();
        for ( int y = 0; y < NES_DISP_HEIGHT*NES_DISP_WIDTH; y++ )
        {

            quint16 r= ( ( WorkFrame[y] & 0x7c00 ) /*>> 7*/ );
            quint16 g =( ( WorkFrame[y] & 0x03e0 ) /*>> 2 */);
            quint16 b =( ( WorkFrame[y] & 0x001f ) /*<< 3 */);

            imgp[y] = (r<<1)|(g<<1)|(b);
        }
        update();
    }
//    workerThread->set_quit(1);
}

void Widget::initAudio()
{
    QAudioFormat format;
    format.setSampleRate(44100);
    format.setChannelCount(1);
    format.setSampleSize(16);
    format.setCodec("audio/pcm");
    format.setByteOrder(QAudioFormat::LittleEndian);
    format.setSampleType(QAudioFormat::SignedInt);

    QAudioDeviceInfo dev = QAudioDeviceInfo::defaultInputDevice();
    if (!dev.isFormatSupported(format)) {
        qWarning() << "Default format not supported - trying to use nearest";
        format = dev.nearestFormat(format);
    }
    m_generator.reset(new Generator(format, 1 * 1000000, 600));
    m_audioOutput.reset(new QAudioOutput(dev, format));
    m_generator->start();
    m_audioOutput->start(m_generator.data());
//    qreal initialVolume = QAudio::convertVolume(m_audioOutput->volume(),
//                                                QAudio::LinearVolumeScale,
//                                                QAudio::LogarithmicVolumeScale);
    m_audioOutput->setVolume(1.0);
}




void WorkerThread::set_file_name(QString fn)
{
    nes_file_name = fn;
}

void WorkerThread::run()
{
    quint8 flag = start_application(/*QString("E:\\test\\infonesgames\\12345.nes")*/nes_file_name);
    if(!flag){
        qDebug()<<"读取文件错误"<<"InfoNES_loop quit";
        return;
    }
    while(1){

        QThread::msleep(0);
        InfoNES_loop();
        if(quit){//退出前可以处理内存清除等工作
            qDebug()<<"InfoNES_loop quit";
            infoNes_clean();
            break;
        }

        if(LoadFrame_flag){
            emit update_img_signal(LoadFrame_flag);
            LoadFrame_flag =0;
        }
    }
}



Generator::Generator(const QAudioFormat &format
    , qint64 durationUs
    , int sampleRate)
{
    Q_UNUSED(format);
    Q_UNUSED(durationUs);
    Q_UNUSED(sampleRate);
//    if (format.isValid())
    //        generateData(format, durationUs, sampleRate);
    m_buffer.resize(2048*4);//4k*16位
}

Generator::~Generator()
{
    stop();
}

void Generator::start()
{
    open(QIODevice::ReadOnly);
}

void Generator::stop()
{
    m_pos = 0;
    close();
}
/*
void Generator::generateData(const QAudioFormat &format, qint64 durationUs, int sampleRate)
{
    const int channelBytes = format.sampleSize() / 8;
    const int sampleBytes = format.channelCount() * channelBytes;
    qint64 length = (format.sampleRate() * format.channelCount() * (format.sampleSize() / 8))
                        * durationUs / 1000000;
    Q_ASSERT(length % sampleBytes == 0);
    Q_UNUSED(sampleBytes) // suppress warning in release builds

    m_buffer.resize(length);
    unsigned char *ptr = reinterpret_cast<unsigned char *>(m_buffer.data());
    int sampleIndex = 0;


    while (length) {
        // Produces value (-1..1)
        const qreal x = qSin(2 * M_PI * sampleRate * qreal(sampleIndex++ % format.sampleRate()) / format.sampleRate());
        for (int i=0; i<format.channelCount(); ++i) {
//            if (format.sampleSize() == 8) {
//                if (format.sampleType() == QAudioFormat::UnSignedInt) {
//                    const quint8 value = static_cast<quint8>((1.0 + x) / 2 * 255);
//                    *reinterpret_cast<quint8 *>(ptr) = value;
//                } else if (format.sampleType() == QAudioFormat::SignedInt) {
//                    const qint8 value = static_cast<qint8>(x * 127);
//                    *reinterpret_cast<qint8 *>(ptr) = value;
//                }
//            } else if (format.sampleSize() == 16) {
//                if (format.sampleType() == QAudioFormat::UnSignedInt) {
//                    quint16 value = static_cast<quint16>((1.0 + x) / 2 * 65535);
//                    if (format.byteOrder() == QAudioFormat::LittleEndian)
//                        qToLittleEndian<quint16>(value, ptr);
//                    else
//                        qToBigEndian<quint16>(value, ptr);
//                } else if (format.sampleType() == QAudioFormat::SignedInt) {
                    qint16 value = static_cast<qint16>(x * 32767);
                    if (format.byteOrder() == QAudioFormat::LittleEndian)
                        qToLittleEndian<qint16>(value, ptr);
                    else
                        qToBigEndian<qint16>(value, ptr);
//                }
//            }

            ptr += channelBytes;
            length -= channelBytes;
        }
    }
}*/
extern BYTE final_wave[16384];
extern int wavflag;
qint64 Generator::readData(char *data, qint64 len)
{

//    unsigned char *ptr = reinterpret_cast<unsigned char *>(m_buffer.data());
//    if ( wavflag )
//    {
//        wavflag = 0;
//    }
//     m_pos
//    quint16 *d = (quint16*)data;
    for(int i=0;i<len;i++)
    {
        data[i++]=final_wave[m_pos]>>8;
        data[i]=final_wave[m_pos];
//        qToLittleEndian<quint16>(final_wave[m_pos],d);
//        d[i]=final_wave[m_pos];
//        d++;
        m_pos++;
        if(m_pos>=16384*2){
            m_pos = 0;
        }
    }
//    qDebug()<<len;
    return len;
}

qint64 Generator::writeData(const char *data, qint64 len)
{
    Q_UNUSED(data);
    Q_UNUSED(len);

    return 0;
}

qint64 Generator::bytesAvailable() const
{
    return m_buffer.size() + QIODevice::bytesAvailable();
}
